Autocomplete, the menu and the element bound to.

Autocomplete, the menu and the element bound to.

Hi all

Having problems running some code based on one of the samples with a custom source so using an ajax request. Works up to the point when a value is selected. The input field is set with the value of the option rather than the label. This seems to happen in the menu widget when it sets self.element.val(item.value) which would work fine if the autocomplete was created on the select but it isn't in the sample. Its set on the input. If I change the code to create the autocomplete on the select then the UI is broken because the positioning of the menu is way off to the left. I've tried to change the styling (the menudocking stuff) but its not behaving for me. Any ideas welcome.

Heres my code. First the code behind...

  1.     public partial class WebForm1 : System.Web.UI.Page
  2.     {
  3.         [Serializable]
  4.         private class CustomObject
  5.         {
  6.             public String Name { get; set; }
  7.             public Int32 Value { get; set; }
  8.         }
  9.         protected void Page_Load(object sender, EventArgs e)
  10.         {

  11.         }

  12.         [WebMethod(EnableSession = true)]
  13.         public static jsSearchResult getData()
  14.         {
  15.             List<CustomObject> list = new List<CustomObject>();
  16.             CustomObject obj = new CustomObject() { Name = "Leeds", Value = 1 };
  17.             list.Add(obj);
  18.             obj = new CustomObject() { Name = "London", Value = 2 };
  19.             list.Add(obj);
  20.             obj = new CustomObject() { Name = "Birmingham", Value = 3 };
  21.             list.Add(obj);


  22.             jsSearchResult returnObject = new jsSearchResult()
  23.             {
  24.                 Data = list,
  25.                 TotalCount = 4
  26.             };

  27.             return returnObject;
  28.         }
  29.     }

Now the markup:

  1. <meta charset="UTF-8" />
  2. <script type="text/javascript">
  3. (function($) {
  4. $.widget("ui.combobox", {
  5. _create: function() {
  6. var self = this;
  7. var select = this.element.hide();

  8. var u = this.options.url;
  9. var p = this.options.params;
  10. var m = this.options.mapper;
  11. var f = this.options.error;
  12. var pageObject = this.options.pageObject;
  13. var text = pageObject[this.options.propertyText];
  14. var value = pageObject[this.options.propertyValue];
  15. var propValueName = this.options.propertyValue;

  16. if (text && value) {
  17.    // update the select
  18.    var opts = { value: text };

  19.    $.each(opts, function(val, text) {
  20.        $(select).append($('<option></option>').val(val).html(text));
  21.    });

  22.    // update the input with the text of the returned item
  23.    $(input).val(text);
  24. }

  25. var input = $("<input>")
  26. .insertAfter(select)
  27. .autocomplete({
  28. source: function(request, response) {
  29. // var matcher = new RegExp(request.term, "i");
  30. // response(select.children("option").map(function() {
  31. // var text = $(this).text();
  32. // if (!request.term || matcher.test(text))
  33. // return {
  34. // id: $(this).val(),
  35. // label: text.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + request.term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"),
  36. // value: text
  37. // };
  38. // }));
  39.    $.ajax({
  40.        type: "POST",
  41.        url: u,
  42.        dataType: "json",
  43.        data: p,
  44.        contentType: "application/json; charset=utf-8",
  45.        success: function(data) {
  46.            if ($.isFunction(m)) {
  47.                var selectcontent = m(data.d);
  48.                response(selectcontent);
  49.                select.empty();
  50.                $.each(selectcontent, function(val, text) {
  51.                    $(select).append($('<option></option>').val(text.value).html(text.label));
  52.                });
  53.            }
  54.        },
  55.        error: f
  56.    })
  57. },
  58. delay: 0,
  59. select: function(e, ui) {
  60. if (!ui.item) {
  61. // remove invalid value, as it didn't match anything
  62. $(this).val("");
  63. return false;
  64. }
  65. $(this).focus();
  66. select.val(ui.item.id);
  67. self._trigger("selected", null, {
  68. item: select.find("[value='" + ui.item.id + "']")
  69. });
  70. },
  71. minLength: 0
  72. })
  73. .addClass("ui-widget ui-widget-content ui-corner-left");
  74. $("<button>&nbsp;</button>")
  75. .insertAfter(input)
  76. .button({
  77. icons: {
  78. primary: "ui-icon-triangle-1-s"
  79.            },
  80. label: '',
  81. text: false
  82. }).removeClass("ui-corner-all")
  83. .addClass("ui-corner-right ui-button-icon")
  84. .position({
  85. my: "left center",
  86. at: "right center",
  87. of: input,
  88. offset: "-1 0"
  89. }).css("top", "")
  90. .click(function() {
  91. // close if already visible
  92. if (input.autocomplete("widget").is(":visible")) {
  93. input.autocomplete("close");
  94. return;
  95. }
  96. // pass empty string as value to search for, displaying all results
  97. input.autocomplete("search", "");
  98. input.focus();
  99. });
  100. },
  101. options: { // initial values are stored in the widget's prototype
  102.    url: '../WebForm1.aspx/getData',
  103.    params: {},
  104.    input: {},
  105.    pageObject: {},
  106.    propertyText: null,
  107.    propertyValue: null,
  108.    doSearchOnEmpty: true,
  109.    dropdownData: null,
  110.    menudocking: {
  111.        menucorner: "right top",
  112.        inputcorner: "right bottom",
  113.        collision: "none"
  114.    },
  115.    mapper: function(data) {
  116.        // This default mapper method is used if the response is successful.
  117.        // It maps the elements for the option text and value. Below, the 
  118.        // item.Name & item.Value are the properties of an element in the
  119.        // collection returned by the pageMethod so supply your own mapper if
  120.        // your elements have a different property.
  121.        return $.map(data.Data, function(item) {
  122.            return {
  123.                label: item.Name,
  124.                value: item.Value
  125.            }
  126.        })
  127.    },
  128.    error: function(request, message, exception) {
  129.        if (message == "error") {
  130.            alert("The parameters to the the request are probably invalid.");
  131.        }
  132.        else {
  133.            alert(message);
  134.        }
  135.    }
  136. }
  137. });

  138. })(jQuery);

  139. $(function() {
  140.    $("select").combobox({
  141.        url: '../WebForm1.aspx/getData',
  142.        propertyText: 'DropdownText',
  143.        propertyValue: 'DropdownValue'
  144.    });
  145. });
  146. </script>
  147. <style>
  148. /* TODO shouldn't be necessary */
  149. .ui-button-icon-only .ui-button-text { padding: 0.35em; } 
  150. .ui-autocomplete-input { padding: 0.48em 0 0.47em 0.45em; }
  151. </style>


  152. <div class="demo">

  153. <div class="ui-widget">
  154. <label>Your preferred programming language: </label>
  155. <select>
  156. </select>
  157. </div>
  158. <div class="ui-widget">
  159. <label>Your preferred programming language: </label>
  160. <select>
  161. </select>
  162. </div>

  163. </div><!-- End demo -->

  164. <div class="demo-description">
  165. <p>
  166. A custom widget built by composition of Autocomplete and Button. You can either type something into the field to get filtered suggestions based on your input, or use the button to get the full list of selections.
  167. </p>
  168. <p>
  169. The input is read from an existing select-element for progressive enhancement, passed to Autocomplete with a customized source-option.
  170. </p>
  171. </div><!-- End demo-description -->


Thanks
Matt